<script setup lang="ts">
import {computed, onMounted, onUnmounted, ref, watch} from 'vue';
import QuestionContainer from "./components/QuestionContainer.vue";
import Resizer from "../../../components/Resizer.vue";
import {DocumentChecked, Edit, VideoPlay} from "@element-plus/icons-vue";
import {useRoute} from "vue-router";
import {
  ChoiceOptionVO,
  JudgeControllerService,
  QuestionControllerService,
  QuestionVO,
  SetControllerService,
  SetDetailVO, TestCaseVO
} from "../../../../generated";
import {ElMessage} from "element-plus";
import {eventBus} from '@/utils/eventBus.ts'
import ResultPopup from "./ResultPopup.vue";
import Tab from "./components/Tab.vue";
import {useUserStore} from "@/stores/userStore.ts";
import {QuestionType} from "@/views/question/addQuestion/types/questionTypes.ts";
import AnswerArea from "./components/AnswerArea.vue";
import ProgrammingEditor from "./components/ProgrammingEditor.vue";
import QuestionInfo from "./components/QuestionInfo.vue";

let userStore = useUserStore();
const questionWidth = ref(48);
const codeHeight = ref(60);
const code = ref('');

const language = ref('');

interface Result {
  result: string;
}

interface SubmitResult {
  questionName?: string;
  username?: string;
  submitTime?: string;
  judgeTime?: string;
  compiler?: string;
  memory?: string;
  time?: string;
  status?: number;
  score?: string;
  testCaseList?: TestCaseVO[];
  code?: string;
  compilerOutput?: string;
  errorMessage?: string;
  showWaitingInfo?: boolean;
  waitingInfo?: string;
  questionType?: QuestionType;
  userInput?: string;
  choiceOptionList?: ChoiceOptionVO[];
  judgement?: number;
  fillBlanks?: string[];
  comprehensive?: string;
  analysis?: string;
  suggestion?: string;
  referenceAnswer?: string;
}

const data = ref<QuestionVO>({
  title: "",
  content: "",
  difficulty: 0,
  language: [],
  tagList: [],
  submitNum: 0,
  acceptedNum: 0,
  timeLimit: 0,
  memoryLimit: 0,
  thumbNum: 0,
  favourNum: 0,
  isThumb: false,
  isFavour: false,
  type: QuestionType.PROGRAMMING,
  choiceOptionList: [],
  fillBlankNum: 0
})

let route = useRoute();

const isMobile = ref(false)

const checkMobile = () => {
  isMobile.value = window.innerWidth <= 768

}

const showResult = ref(false)
const showTab = ref(false)
const judgeResult = ref<SubmitResult>({})

const submissionId = ref<string>('');
const ws = ref<WebSocket | null>(null);

const testCase = ref('');

const activeTab = ref('testCase');

const testResult = ref<Result>({
  result: ''
});

const userAnswer = ref({
  multipleChoice: null,
  judgement: null,
  fillBlanks: [] as string[],
  comprehensive: ''
})

const fetchQuestionDetail = async () => {
  const questionId = String(route.params.id);

  const res = await QuestionControllerService.getQuestionByIdUsingGet(questionId);
  if (res.code === 0 && res.data) {
    data.value = res.data;
    if (res.data?.language) {
      language.value = res.data?.language[0]
    }
  } else {
    ElMessage.error(res.message)
  }
}

const set = ref<SetDetailVO>({
  id: '',
  groupList: [],
  tagList: [],
  title: '',
  target: '',
  description: ''
})

const fetchTabInfo = async () => {
  let mode = route.query.mode;
  if (!mode) {
    return;
  }

  let envId = route.query.envId;
  if (!envId) {
    return;
  }

  let res = await SetControllerService.getSetDetailUsingGet(envId as string);
  if (res.code === 0 && res.data) {
    set.value = res.data
  }
}

// 监听路由变化
watch(() => route.params.id, async (newId) => {
  if (newId) {
    await fetchQuestionDetail();
  }
})

const handleSubmitTestCase = async () => {
  const res = await JudgeControllerService.testCodeUsingPost({
    code: code.value,
    language: language.value,
    testCase: testCase.value
  });

  if (res.code === 0 && res.data) {
    testResult.value = res.data;
    activeTab.value = 'result';
  } else {
    ElMessage.error(res.message || '运行测试失败');
  }
}

const checkHasLast = async () => {
  let res = await JudgeControllerService.hasLastJudgeResultUsingGet(Number(route.params.id));
  if (res.code === 0) {
    eventBus.emit('updateLastDisabled', !res.data);
  }
}

onMounted(async () => {
  try {
    checkMobile()
    window.addEventListener('resize', checkMobile)
    // 获取题目信息
    await fetchQuestionDetail();
    await fetchTabInfo();
    await checkHasLast();

    // 注册事件监听
    eventBus.on('submitCode', handleSubmitCode);
    eventBus.on('showTab', () => {
      showTab.value = true;
    });
    eventBus.on('closeTab', () => {
      showTab.value = false;
    });
    eventBus.on('showLast', handleShowLast);
  } catch (error) {
    console.error('Error in mounted hook:', error);
  }
});

// 将提交代码的处理逻辑抽取为单独的函数
const handleSubmitCode = async () => {
  try {
    closeWebSocket();
    const res = await JudgeControllerService.judgeUsingPost({
      setId: route.query.envId as string,
      questionId: route.params.id as string,
      code: code.value,
      language: language.value,
      multipleChoice: userAnswer.value.multipleChoice ?? [],
      judgement: userAnswer.value.judgement ?? 0,
      fillBlanks: userAnswer.value.fillBlanks ?? [],
      comprehensive: userAnswer.value.comprehensive ?? ''
    });
    showResult.value = true;
    if (res.code === 0 && res.data) {
      judgeResult.value = res.data;
      judgeResult.value.questionType = data.value.type;
      submissionId.value = res.data.submissionId;
      let info = await JudgeControllerService.getWaitingCountUsingGet();
      if (info.code === 0 && info.data) {
        judgeResult.value.showWaitingInfo = info.data > 1;
        if (judgeResult.value.showWaitingInfo) {
          judgeResult.value.waitingInfo = "前方还有 " + info.data + " 人";
        }
      }
      connectWebSocket();
    } else {
      ElMessage.error(res.message || '提交失败');
    }
  } catch (error) {
    ElMessage.error('提交代码失败');
  }
};

// 将显示上次结果的处理逻辑抽取为单独的函数
const handleShowLast = async () => {
  try {
    showResult.value = true;
    const result = await JudgeControllerService.getLastJudgeResultUsingGet(route.params.id as string);
    if (result.code === 0 && result.data) {
      judgeResult.value = result.data;
    }
  } catch (error) {
    console.error('Error showing last result:', error);
  }
};

onUnmounted(() => {
  try {
    // 移除所有事件监听
    eventBus.off('submitCode', handleSubmitCode);
    eventBus.off('showTab');
    eventBus.off('closeTab');
    eventBus.off('showLast', handleShowLast);
    closeWebSocket();
    window.removeEventListener('resize', checkMobile);
  } catch (error) {
    console.error('Error in unmounted hook:', error);
  }
});

const connectWebSocket = () => {
  const wsUrl = `ws://localhost:8080/api/ws/judge?submissionId=${submissionId.value}`;
  ws.value = new WebSocket(wsUrl);

  ws.value.onopen = () => {
    console.log('WebSocket连接已建立');
  };

  ws.value.onmessage = async (event) => {
    try {
      const message = JSON.parse(event.data);

      switch (message.type) {
        case 0:
          judgeResult.value.status = 0;
          break;
        case 1:
          judgeResult.value.status = 1;
          judgeResult.value.showWaitingInfo = false;
          break;
        case 3:
          ElMessage.error('系统错误，请联系管理员');
          break;
        default:
          const result = await JudgeControllerService.getJudgeResultUsingGet(submissionId.value);
          if (result.code === 0 && result.data) {
            judgeResult.value = result.data;
          }
          closeWebSocket();
          break;
      }
    } catch (error) {
      console.error('处理WebSocket消息失败:', error);
    }
  };

  ws.value.onerror = (error) => {
    console.error('WebSocket错误:', error);
    ElMessage.error('评测连接出错');
  };

  ws.value.onclose = () => {
    console.log('WebSocket连接已关闭');
  };
};

const closeWebSocket = () => {
  if (ws.value && ws.value.readyState === WebSocket.OPEN) {
    ws.value.close();
    ws.value = null;
  }
};

// 添加计算属性判断是否为编程题
const isProgrammingQuestion = computed(() => {
  return data.value.type === QuestionType.PROGRAMMING
})
</script>

<template>
  <result-popup
      v-model:visible="showResult"
      :result="judgeResult"
  />
  <Tab
      v-model:showTab="showTab"
      :set="set"
      :mode="route.query.mode as string"
  />
  <div class="question-detail-view">
    <el-container v-if="isProgrammingQuestion" class="container">
      <el-aside class="aside question-aside" :style="isMobile ? {} : { width: `${questionWidth}%` }">
        <question-container>
          <template #header>
            <QuestionInfo
                :question-data="data"
                :is-programming-question="isProgrammingQuestion"
                render-part="header"
            />
          </template>

          <template #main>
            <QuestionInfo
                :question-data="data"
                :is-programming-question="isProgrammingQuestion"
                render-part="main"
            />
          </template>

          <template #footer>
            <QuestionInfo
                :question-data="data"
                :is-programming-question="isProgrammingQuestion"
                render-part="footer"
            />
          </template>
        </question-container>
      </el-aside>

      <Resizer
          v-if="!isMobile"
          direction="horizontal"
          :min-percent="30"
          :max-percent="70"
          v-model="questionWidth"
      />

      <!-- 桌面端代码编辑器 -->
      <el-aside v-if="!isMobile" class="aside code-aside" :style="{ width: `${100 - questionWidth}%` }">
        <el-container class="code-container">
          <el-main class="code-main" :style="{ height: `${codeHeight}%` }">
            <question-container :show-footer="false">
              <template #header>
                <div style="display: flex; align-items: center">
                  <el-icon color="#03B128" style="margin-right: 5px">
                    <Edit/>
                  </el-icon>
                  <div class="submission-title">代码</div>
                </div>
              </template>

              <template #main>
                <div class="code-editor">
                  <ProgrammingEditor
                      :language="language"
                      :languages="data.language || []"
                      :isMobile="false"
                      v-model:code="code"
                      @update:language="val => language = val"
                      @submit-code="handleSubmitCode"
                  />
                </div>
              </template>
            </question-container>
          </el-main>

          <Resizer
              v-if="!isMobile"
              direction="vertical"
              :min-percent="30"
              :max-percent="80"
              v-model="codeHeight"
          />

          <el-footer v-if="!isMobile" class="test-footer" :style="{ height: `${100 - codeHeight}%` }">
            <question-container :show-footer="false">
              <template #header>
                <div style="display: flex; align-items: center; width: 100%;">
                  <div style="display: flex; align-items: center; cursor: pointer" @click="activeTab = 'testCase'">
                    <el-icon :color="activeTab === 'testCase' ? '#03B128' : '#999'" style="margin-right: 5px">
                      <DocumentChecked/>
                    </el-icon>
                    <div class="submission-title" :style="{ color: activeTab === 'testCase' ? '#1A1A1A' : '#999' }">
                      测试用例
                    </div>
                  </div>

                  <template v-if="testResult.result!==''">
                    <div style="width: 1px; height: 14px; background-color: #dcdfe6; margin: 0 12px"/>

                    <div style="display: flex; align-items: center; cursor: pointer" @click="activeTab = 'result'">
                      <el-icon :color="activeTab === 'result' ? '#03B128' : '#999'" style="margin-right: 5px">
                        <document-checked/>
                      </el-icon>
                      <div class="submission-title" :style="{ color: activeTab === 'result' ? '#1A1A1A' : '#999' }">
                        运行结果
                      </div>
                    </div>
                  </template>
                </div>
              </template>

              <template #main>
                <div class="test-cases">
                  <template v-if="activeTab === 'testCase'">
                    <el-input
                        v-model="testCase"
                        type="textarea"
                        :rows="8"
                        placeholder="请输入测试用例..."
                        resize="none"
                        class="test-input"
                    />

                    <div class="test-button">
                      <el-button type="primary" size="default" color="#03B128" @click="handleSubmitTestCase"
                                 :disabled="!userStore.isLogin">
                        <el-icon>
                          <video-play/>
                        </el-icon>
                        运行测试
                      </el-button>
                    </div>
                  </template>

                  <template v-else>
                    <div class="test-result">
                      <el-empty description="暂无运行结果" v-if="!testResult"/>
                      <div v-else>
                        {{ testResult.result }}
                      </div>
                    </div>
                  </template>
                </div>
              </template>
            </question-container>
          </el-footer>
        </el-container>
      </el-aside>

      <!-- 移动端代码编辑器 -->
      <div v-if="isMobile" class="mobile-code-editor">
        <question-container :show-footer="false">
          <template #header>
            <div style="display: flex; justify-content: space-between; width: 100%; align-items: center">
              <div style="display: flex; align-items: center">
                <el-icon color="#03B128" style="margin-right: 5px">
                  <Edit/>
                </el-icon>
                <div class="submission-title">代码</div>
              </div>
            </div>
          </template>

          <template #main>
            <div class="code-editor">
              <ProgrammingEditor
                  :language="language"
                  :languages="data.language || []"
                  :isMobile="true"
                  v-model:code="code"
                  @update:language="val => language = val"
                  @submit-code="handleSubmitCode"
              />
            </div>
          </template>
        </question-container>

        <!-- 移动端测试用例部分 -->
        <question-container :show-footer="false" class="mobile-test-case">
          <template #header>
            <div style="display: flex; align-items: center; width: 100%;">
              <div style="display: flex; align-items: center; cursor: pointer" @click="activeTab = 'testCase'">
                <el-icon :color="activeTab === 'testCase' ? '#03B128' : '#999'" style="margin-right: 5px">
                  <DocumentChecked/>
                </el-icon>
                <div class="submission-title" :style="{ color: activeTab === 'testCase' ? '#1A1A1A' : '#999' }">测试用例
                </div>
              </div>

              <template v-if="testResult.result!==''">
                <div style="width: 1px; height: 14px; background-color: #dcdfe6; margin: 0 12px"/>
                <div style="display: flex; align-items: center; cursor: pointer" @click="activeTab = 'result'">
                  <el-icon :color="activeTab === 'result' ? '#03B128' : '#999'" style="margin-right: 5px">
                    <document-checked/>
                  </el-icon>
                  <div class="submission-title" :style="{ color: activeTab === 'result' ? '#1A1A1A' : '#999' }">运行结果
                  </div>
                </div>
              </template>
            </div>
          </template>

          <template #main>
            <div class="test-cases">
              <template v-if="activeTab === 'testCase'">
                <el-input
                    v-model="testCase"
                    type="textarea"
                    :rows="6"
                    placeholder="请输入测试用例..."
                    resize="none"
                    class="test-input"
                />

                <div class="test-button">
                  <el-button type="primary" size="default" color="#03B128" @click="handleSubmitTestCase"
                             :disabled="!userStore.isLogin">
                    <el-icon>
                      <video-play/>
                    </el-icon>
                    运行测试
                  </el-button>
                </div>
              </template>

              <template v-else>
                <div class="test-result">
                  <el-empty description="暂无运行结果" v-if="!testResult"/>
                  <div v-else>
                    {{ testResult.result }}
                  </div>
                </div>
              </template>
            </div>
          </template>
        </question-container>
      </div>
    </el-container>

    <!-- 非编程题布局 -->
    <div v-else class="non-programming-container">
      <!-- 题目描述区域 -->
      <div class="question-description">
        <question-container>
          <template #header>
            <QuestionInfo
                :question-data="data"
                :is-programming-question="isProgrammingQuestion"
                render-part="header"
            />
          </template>

          <template #main>
            <QuestionInfo
                :question-data="data"
                :is-programming-question="isProgrammingQuestion"
                render-part="main"
            />
          </template>

          <template #footer>
            <QuestionInfo
                :question-data="data"
                :is-programming-question="isProgrammingQuestion"
                render-part="footer"
            />
          </template>
        </question-container>
      </div>

      <!-- 非编程题答题区域 -->
      <div class="answer-section">
        <question-container class="answer-container">
          <template #header>
            <div style="display: flex; align-items: center">
              <el-icon color="#03B128" style="margin-right: 5px">
                <Edit/>
              </el-icon>
              <div class="submission-title">答题区域</div>
            </div>
          </template>

          <template #main>
            <AnswerArea
                :question-type="data.type"
                :options="data.choiceOptionList"
                :fill-blank-num="data.fillBlankNum"
                :is-multiple="data.isMultiple === 1"
                v-model="userAnswer"
            />
          </template>
        </question-container>
      </div>
    </div>
  </div>
</template>

<style scoped>
.question-detail-view {
  height: calc(100vh - 60px);
  padding: 16px;
  background-color: #f5f6f7;
  max-width: 100%;
  box-sizing: border-box;
}

.container {
  height: 100%;
  display: flex;
  justify-content: center;
  gap: 0;
}

.non-programming-container {
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  overflow-y: auto;
}

.question-description,
.answer-section {
  width: 50%;
  margin-bottom: 16px;
}

.aside {
  height: 100%;
}

.question-aside {
  width: v-bind('`${questionWidth}%`') !important;
}

.code-aside {
  width: v-bind('`${100 - questionWidth}%`') !important;
}

.code-container {
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: 0;
}

.code-main {
  padding: 0;
  height: 60%;
  position: relative;
}

.test-footer {
  height: 40%;
  padding: 0;
}

.submission-title {
  font-size: 14px;
  color: #1A1A1A;
  margin-right: 10px;
}

.question-content {
  padding: 20px 16px;
}

.question-content h2 {
  margin: 0;
}

:deep(.question-container) {
  height: 100%;
}

.test-cases {
  padding: 12px 16px;
  box-sizing: border-box;
  height: 100%;
  display: flex;
  flex-direction: column;
}

.test-input {
  flex: 1;
  margin-bottom: 12px;
}

.test-button {
  display: flex;
  justify-content: flex-end;
}

.code-editor {
  height: 100%;
  box-sizing: border-box;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.language-selector {
  padding: 8px 12px;
  border-bottom: 1px solid #e4e7ed;
  background-color: #ffffff;
}

.selector-container {
  display: flex;
  align-items: center;
  gap: 10px;
}

.language-select {
  width: 100px;
}

.question-stats {
  margin-top: 20px;
  margin-bottom: 20px;
  padding: 0 16px;
  display: flex;
  gap: 20px;
}

.stat-item {
  display: flex;
  align-items: center;
  gap: 10px;
}

.stat-label {
  font-size: 12px;
  color: rgba(38, 38, 38, 0.75);
}

.stat-value {
  font-size: 14px;
  color: #262626;
  font-weight: 600;
}

.footer-thumb {
  width: 73px;
  height: 28px;
  border-radius: .5rem;
}

/* 添加点赞按钮激活状态样式 */
.footer-thumb.el-button--primary {
  background-color: #007CFD;
  border-color: #007CFD;
  color: #fff;
}

.divider {
  width: 2px;
  height: 18px;
  background-color: #dcdfe6;
}

.footer-divider {
  width: 1px;
  height: 16px;
  background-color: #dcdfe6;
  margin-left: 10px;
}

.footer-icon {
  width: 28px;
  margin-left: 4px;
  padding: 6px
}

.footer-icon.el-button--primary {
  color: #FFB800;
}

.edit-button {
  cursor: pointer;
}

.edit-button:hover .submission-title {
  color: #007CFD;
}

:deep(.el-textarea) {
  height: 100%;
}

:deep(.el-textarea__inner) {
  height: 100% !important;
  box-sizing: border-box;
}

.test-result {
  height: 100%;
  padding: 12px;
  overflow-y: auto;
}

/* 添加移动端样式 */
@media screen and (max-width: 768px) {
  .container {
    flex-direction: column;
    padding: 8px;
    gap: 12px;
    height: auto;
  }

  .question-aside {
    width: 100% !important;
    height: auto;
  }

  .question-description,
  .answer-section {
    width: 100%;
  }

  .mobile-code-editor {
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 12px;
  }

  .code-editor {
    height: 400px;
  }

  .mobile-test-case {
    margin-bottom: 16px;
  }

  .test-cases {
    padding: 12px;
  }

  .test-input {
    margin-bottom: 12px;
  }

  .test-button {
    display: flex;
    justify-content: flex-end;
  }

  .language-selector {
    padding: 8px;
    border-bottom: 1px solid #e4e7ed;
  }

  .selector-container {
    display: flex;
    align-items: center;
    gap: 8px;
  }

  .question-content {
    padding: 12px;
  }

  .question-stats {
    padding: 0 12px;
    gap: 12px;
  }

  .el-button {
    padding: 8px 15px;
    font-size: 14px;
  }
}

.limits-container {
  padding: 0 16px 20px;
  display: flex;
  gap: 16px;
}

.limit-card {
  flex: 1;
}

:deep(.el-card__header) {
  padding: 12px;
  border-bottom: 1px solid #e4e7ed;
}

:deep(.el-card__body) {
  padding: 12px;
}

.limit-header {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  color: #606266;
}

.limit-value {
  font-size: 16px;
  font-weight: 600;
  color: #303133;
  text-align: center;
}

/* 移动端适配 */
@media screen and (max-width: 768px) {
  .limits-container {
    padding: 0 12px 16px;
    gap: 12px;
  }

  .limit-value {
    font-size: 14px;
  }
}

/* 添加非编程题样式 */
.non-programming .question-aside {
  width: 50% !important;
  margin: 0 auto;
}

.non-programming .container {
  justify-content: center;
  flex-direction: column;
  align-items: center;
}

/* 答题区域样式 */
.answer-wrapper {
  width: 50%;
  margin: 16px auto 0;
}

.answer-container {
  width: 100%;
}

.mobile-answer-area {
  width: 100%;
  margin-top: 16px;
}
</style>
